home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / ddj0190.arc / NELSON.LST < prev    next >
File List  |  1989-12-19  |  17KB  |  431 lines

  1. _LOCATION IS EVERYTHING!_
  2. by Mark Nelson
  3.  
  4. [LISTING ONE]
  5.  
  6. /********************************************************************
  7. **                      ---- LOCATE.C -----
  8. **           Copyright (C) 1989 by Mark R. Nelson
  9. **  Program:  LOCATE.C
  10. **  Author:   Mark R. Nelson
  11. **  Summary:  LOCATE reads in MS-DOS formate EXE files and writes
  12. **            out relocated code in Intel Hex format.  The code
  13. **            segment is relocated to start at F000:0000.  Data
  14. **            is relocated to start at 0040:0000.
  15. ********************************************************************/
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19.  
  20. #define TRUE 1
  21. #define FALSE 0
  22.  
  23. struct exe_header {
  24.                       unsigned int signature;
  25.                       unsigned int image_length_mod_512;
  26.                       unsigned int file_size_in_pages;
  27.                       unsigned int num_of_relocation_table_items;
  28.                       unsigned int size_of_header_in_paragraphs;
  29.                       unsigned int min_num_of_paragraphs_required;
  30.                       unsigned int max_num_of_paragraphs_required;
  31.                       unsigned int disp_of_stack_in_paragraphs;
  32.                       unsigned int initial_sp;
  33.                       unsigned int word_checksum;
  34.                       unsigned int initial_ip;
  35.                       unsigned int disp_of_code_in_paragraphs;
  36.                       unsigned int disp_of_relocation_table;
  37.                       unsigned int overlay_number;
  38.                   } header;
  39.  
  40. FILE *exe_file;
  41. FILE *hex_file;
  42. unsigned char *image;
  43. unsigned long int image_size;
  44. unsigned long int image_offset;
  45. unsigned long first_data_segment_in_exe_file;
  46. int verbose=TRUE;
  47. unsigned int output_base_code_segment=0xF000;
  48. unsigned int output_base_data_segment=0x0040;
  49.  
  50. main(int argc,char *argv[])
  51. {
  52.     printf("Locate 1.0  Copyright (C) 1989 by Mark R. Nelson\n");
  53.  
  54.     open_files(argc,argv);          /* Open the input and output files      */
  55.     read_header_data();             /* Read in the EXE file header          */
  56.     read_input();                   /* Read the code image into a buffer    */
  57.     process_relocation_table();     /* Relocate all segment references      */
  58.     dump_output();                  /* Write the code image to the HEX file */
  59.     output_restart_code();          /* Write the restart code line          */
  60.     output_intel_hex(0,0,1,NULL);   /* Output an EOF record                 */è}
  61.  
  62. /********************************************************************
  63. **                       ---- open_files ----
  64. **   This routine opens an EXE file and a HEX file.  If they are specified
  65. **   on the command line, those names are used.  Otherwise the user is
  66. **   prompted for file names
  67. ********************************************************************/
  68.  
  69. open_files(int argc,char *argv[])
  70. {
  71. char exe_file_name[81];
  72. char hex_file_name[81];
  73.  
  74.     if (argc>1)
  75.         strcpy(exe_file_name,argv[1]);
  76.     else
  77.     {
  78.         printf("EXE file name? ");
  79.         scanf("%s",exe_file_name);
  80.     }
  81.  
  82.     exe_file=fopen(exe_file_name,"rb");
  83.     if (exe_file==NULL)
  84.         fatal_error("Had trouble opening the input file!");
  85.  
  86.     if (argc > 2)
  87.         strcpy(hex_file_name,argv[2]);
  88.     else
  89.     {
  90.         printf("Hex file name? ");
  91.         scanf("%s",hex_file_name);
  92.     }
  93.  
  94.     hex_file=fopen(hex_file_name,"w");
  95.     if (hex_file==NULL)
  96.         fatal_error("Had trouble opening the output file!");
  97.  
  98. }
  99.  
  100. /********************************************************************
  101. **                     ---- read_header_data ----
  102. **   This routine reads in the EXE header structure and computes both
  103. **   the image offset and size.  The compuataions are all done using
  104. **   numbers found in the header.  This program arbitrarily limits
  105. **   the code image size to 64K, but could easily be expanded to go
  106. **   to larger sizes.
  107. ********************************************************************/
  108.  
  109. read_header_data()
  110. {
  111.     if (fread(&header,sizeof(struct exe_header),1,exe_file) != 1)
  112.         fatal_error("Couldn't read header from file!");
  113.     if (verbose)
  114.         print_header();è    image_offset=header.size_of_header_in_paragraphs*16;
  115.     image_size = (header.file_size_in_pages-1)*512;
  116.     image_size -= image_offset;
  117.     image_size += header.image_length_mod_512;
  118.     if (image_size > 0xFFFFL)
  119.         fatal_error("The EXE image is larger than I can handle!");
  120.     first_data_segment_in_exe_file=header.disp_of_stack_in_paragraphs;
  121. }
  122.  
  123. /********************************************************************
  124. **                       ---- read_input --
  125. **   This routine reads the code image into a buffer.  Any trouble with
  126. **   the buffer or the file generates a fatal error.
  127. ********************************************************************/
  128.  
  129. read_input()
  130. {
  131.     image=malloc(image_size);
  132.     if (image==NULL)
  133.         fatal_error("Couldn't allocate output image space!");
  134.     if (fseek(exe_file,image_offset,SEEK_SET) != 0)
  135.         fatal_error("Couldn't seek to image in the input file!");
  136.     if (fread(image,1,(int)image_size,exe_file) != (int)image_size)
  137.         fatal_error("Couldn't read in the image!");
  138. }
  139.  
  140. /********************************************************************
  141. **                ---- process_relocation_table ----
  142. **   This routine loops through all of the entries in the relocation
  143. **   table.  Each entry points to a segment value in the code image.
  144. **   That segment value is checked to see if it points to code or
  145. **   data.  If it points to data, it is relocated to start at the
  146. **   output_base_data_segment.  Code segments are relocated to start
  147. **   at output_base_code_segment.
  148. ********************************************************************/
  149.  
  150. process_relocation_table()
  151. {
  152. int i;
  153. unsigned int reloc[2];
  154. unsigned long int spot;
  155. unsigned int *guy;
  156. unsigned int old_value;
  157. unsigned int new_value;
  158.  
  159.  fseek(exe_file,(long)header.disp_of_relocation_table,0);
  160.  for (i=0;i<header.num_of_relocation_table_items;i++)
  161.  {
  162.   if (fread(reloc,2,2,exe_file) != 2)
  163.     fatal_error("Couldn't read relocation data from file!");
  164.   printf("Record %3d:  %04X:%04X:",i,reloc[1],reloc[0]);
  165.   spot=reloc[1]*16 + reloc[0];
  166.   old_value=*(int *)(image+spot);
  167.   printf("  was: %04X", old_value);
  168.   if (old_value < first_data_segment_in_exe_file)è   new_value=old_value+output_base_code_segment;
  169.   else
  170.    new_value=old_value-first_data_segment_in_exe_file+output_base_data_segment;
  171.   *(int *)(image+spot)=new_value;
  172.   printf("  now is: %04X\r", new_value);
  173.  }
  174.  printf("\n");
  175. }
  176.  
  177. /********************************************************************
  178. **                   ---- dump_output ----
  179. **   This routine loops the entire code image.  It outputs 34 bytes
  180. **   at a time in Intel Hex format until it is done.  While it is
  181. **   doing this it keeps the user posted by writing the addresses
  182. **   to the screen.  Note that this module would need some modifications
  183. **   to handle images greater than 64K.
  184. ********************************************************************/
  185.  
  186. dump_output()
  187. {
  188. unsigned char *output_pointer;
  189. long int output_size;
  190. int record_size;
  191. unsigned int output_address;
  192. unsigned char segment_address[2];
  193.  
  194.     output_pointer=image;
  195.     output_size=image_size;
  196.     output_address=0;
  197.     segment_address[0]=output_base_code_segment>>8;
  198.     segment_address[1]=output_base_code_segment & 0xff;
  199.     output_intel_hex(2,0,2,segment_address);
  200.     while (output_size > 0)
  201.     {
  202.         printf("%04X\r",output_address);
  203.         record_size=(output_size > 34) ? 34 : output_size;
  204.         output_intel_hex(record_size,output_address,0,output_pointer);
  205.         output_pointer += record_size;
  206.         output_size -= record_size;
  207.         output_address += record_size;
  208.     }
  209.     printf("\n");
  210. }
  211.  
  212. /********************************************************************
  213. **                   ---- output_restart_code ----
  214. **   This routine writes a JMP START instruction out at location
  215. **   at FFFF:0000.  The address of START is contained in the EXE
  216. **   header block.
  217. ********************************************************************/
  218.  
  219. output_restart_code()
  220. {
  221. unsigned char jmp_code[5];
  222. unsigned char segment_address[2];è
  223.     segment_address[0]=0xff;
  224.     segment_address[1]=0xff;
  225.     output_intel_hex(2,0,2,segment_address);
  226.     jmp_code[0]=0xea;                       /*  JMP ????:????             */
  227.     jmp_code[1]=header.initial_ip & 0xff;
  228.     jmp_code[2]=header.initial_ip >> 8;
  229.     header.disp_of_code_in_paragraphs += output_base_code_segment;
  230.     jmp_code[3]=header.disp_of_code_in_paragraphs & 0xff;
  231.     jmp_code[4]=header.disp_of_code_in_paragraphs >> 8;
  232.     header.disp_of_code_in_paragraphs -= output_base_code_segment;
  233.     output_intel_hex(5,0,0,jmp_code);
  234. }
  235.  
  236. /********************************************************************
  237. **                   ---- output_intel_hex ----
  238. **   This routine writes a single record of Intel Hex.
  239. ********************************************************************/
  240.  
  241. output_intel_hex(int size,unsigned int address,int type,unsigned char buffer[])
  242. {
  243. int checksum;
  244. int i;
  245.  
  246.     fprintf(hex_file,":%02X%04X%02X",size,address,type);
  247.     checksum=size+address+(address>>8)+type;
  248.     for (i=0;i<size;i++)
  249.     {
  250.         fprintf(hex_file,"%02X",buffer[i]);
  251.         checksum += buffer[i];
  252.     }
  253.     checksum = -checksum & 0xff;
  254.     fprintf(hex_file,"%02X\n",checksum);
  255. }
  256.  
  257. /********************************************************************
  258. **                     ---- print_header ----
  259. **   This is a routine that lets the program print out the contents
  260. **   of the header.  It is here primarily for assistance in debugging.
  261. ********************************************************************/
  262.  
  263. print_header()
  264. {
  265.     printf("Link program signature:                                    ");
  266.     printf("%4.4X\n",header.signature);
  267.     printf("Length of image mod 512:                                   ");
  268.     printf("%4.4X\n",header.image_length_mod_512);
  269.     printf("Size of file in 512 byte pages, including header:          ");
  270.     printf("%4.4X\n",header.file_size_in_pages);
  271.     printf("Number of relocation table items:                          ");
  272.     printf("%4.4X\n",header.num_of_relocation_table_items);
  273.     printf("Size of header in 16 byte paragraphs:                      ");
  274.     printf("%4.4X\n",header.size_of_header_in_paragraphs);
  275.     printf("Minimum # of 16 byte paragraphs needed above program:      ");
  276.     printf("%4.4X\n",header.min_num_of_paragraphs_required);è    printf("Maximum # of 16 byte paragraphs needed above program:      ");
  277.     printf("%4.4X\n",header.max_num_of_paragraphs_required);
  278.     printf("Displacement of stack within load module in paragraphs:    ");
  279.     printf("%4.4X\n",header.disp_of_stack_in_paragraphs);
  280.     printf("Offset to be loaded in SP:                                 ");
  281.     printf("%4.4X\n",header.initial_sp);
  282.     printf("Word checksum:                                             ");
  283.     printf("%4.4X\n",header.word_checksum);
  284.     printf("Offset to be loaded in IP:                                 ");
  285.     printf("%4.4X\n",header.initial_ip);
  286.     printf("Displacement of code segment in 16 byte paragraphs:        ");
  287.     printf("%4.4X\n",header.disp_of_code_in_paragraphs);
  288.     printf("Displacement of 1st relocation table item:                 ");
  289.     printf("%4.4X\n",header.disp_of_relocation_table);
  290.     printf("Overlay number:                                            ");
  291.     printf("%4.4X\n",header.overlay_number);
  292. }
  293. /********************************************************************
  294. **                     ---- fatal_error ----
  295. **   A self-documenting utility.
  296. ********************************************************************/
  297.  
  298. fatal_error(char *message)
  299. {
  300.     printf(message);
  301.     exit(1);
  302. }
  303.  
  304. [LISTING TWO]
  305.  
  306. ;********************************************************************
  307. ;                        ---- START.ASM ----
  308. ;           Copyright (C) 1989 by Mark R. Nelson
  309. ;  Module:   START.ASM
  310. ;  Author:   Mark R. Nelson
  311. ;  Summary:  This module is an alternate startup routine for Microsoft
  312. ;            or Turbo C programs running on non DOS hardware.  It has
  313. ;            three main jobs.  First, it sets up the segment definitions
  314. ;            so that the STACK segment is the first segment in RAM.
  315. ;            Second, it initializes all predefined data.  Third, it jumps
  316. ;            to the user's main() routine.
  317. ;*******************************************************************
  318.  
  319. ;
  320. ;   Note here that if DGROUP does not contain the stack, which may
  321. ;   be true for larger models, the STACK segment needs to be moved
  322. ;   to be the first one after END_OF_ROM.
  323. ;
  324. ;   Also note that for the startup code to work properly, the first
  325. ;   segment in the data area must be paragraph aligned.  This insures
  326. ;   that for the startup code, the first data segment is exactly 3
  327. ;   larger than the END_OF_ROM segment.
  328. ;
  329. _TEXT              SEGMENT BYTE PUBLIC 'CODE'
  330. _TEXT              ENDS
  331. END_OF_ROM         SEGMENT PARA PUBLIC 'STARTUP_CODE'
  332. END_OF_ROM         ENDS
  333. _CONST             SEGMENT PARA PUBLIC 'CONST'
  334. _CONST             ENDS
  335. _BSS               SEGMENT WORD PUBLIC 'BSS'
  336. _BSS               ENDS
  337. _DATA              SEGMENT WORD PUBLIC 'DATA'
  338. _DATA              ENDS
  339. _STACK             SEGMENT WORD STACK 'STACK'
  340.  
  341. MYSTACK            DB 512 DUP (?)
  342.  
  343. _STACK             ENDS
  344. ;
  345. ;   Note here that if DGROUP does not contain the stack, which may
  346. ;   be true for larger models, the STACK segment needs to be moved
  347. ;   to be the first one after END_OF_ROM.
  348. ;
  349. DGROUP             GROUP   _CONST,_BSS,_DATA,_STACK
  350.  
  351.                    extrn   _main:far
  352.  
  353.                    public  __acrtused        ;This value makes many of the
  354. __acrtused = 9876h                           ;library routines happy
  355.  
  356. END_OF_ROM SEGMENT PARA PUBLIC 'STARTUP_CODE'
  357.  
  358.                    ASSUME  CS:END_OF_ROM
  359. è                   PUBLIC  START
  360.  
  361. START              PROC    FAR
  362.  
  363.                    MOV     AX,DGROUP             ;This code initializes the
  364.                    MOV     SS,AX                 ;SS:SP pair with the proper
  365.                    MOV     SP,OFFSET MYSTACK+512 ;values.
  366. ;
  367. ;   This section of code is charged with moving all predefined values out
  368. ;   of ROM and into RAM.  This is done by copying all values out of the
  369. ;   part of ROM immediately following the last code segment into the
  370. ;   data section.
  371. ;
  372.                    MOV     AX,CS          ;The present code segment is the
  373.                    ADD     AX,3           ;last code segment, and we know
  374.                    MOV     DS,AX          ;that the first data segment will
  375.                                           ;be three up form here.  Put that
  376.                                           ;value into DS
  377.  
  378.                    MOV     AX,DGROUP      ;Now set ES to point to the first
  379.                    MOV     ES,AX          ;section of RAM.
  380.                    XOR     SI,SI          ;SI and DI are the registers
  381.                    XOR     DI,DI          ;used in the MOVSB instruction.
  382.                    MOV     CX,0FBFFH      ;This rep instruction will fill
  383.                    REP     MOVSB          ;everything in a 64K RAM following
  384.                                           ;the interrupt vector space.
  385.  
  386.                    MOV     AX,ES          ;Now set up DS to point to DGROUP
  387.                    MOV     DS,AX
  388.                    STI                    ;Enable interrupts and the jump
  389.                    JMP     _main          ;to the start of the C code
  390.  
  391. START              ENDP
  392.  
  393. END_OF_ROM         ENDS
  394.  
  395.                    END     START
  396.  
  397.  
  398. [LISTING THREE]
  399.  
  400. /********************************************************************
  401. **                      ---- HELLO.C -----
  402. **           Copyright (C) 1989 by Mark R. Nelson
  403. **  Program:  HELLO.C
  404. **  Author:   Mark R. Nelson
  405. **  Summary:  Hello demonstrates the LOCATE program.  It simulates
  406. **            output of a string to a printer on an embedded system.
  407. ********************************************************************/
  408.  
  409. main()
  410. {
  411.  
  412.     my_print("Hello, world!\n");
  413.     while (1) ;
  414. }
  415.  
  416. my_print(char *message)
  417. {
  418.     while (*message)
  419.     {
  420.         if (*message=='\n')
  421.         {
  422.             while ((inportb(0x200) & 0x80) == 0) ;
  423.             outportb(0x200,'\r');
  424.         }
  425.         while ((inportb(0x200) & 0x80) == 0) ;
  426.         outportb(0x200,*message++);
  427.     }
  428. }
  429.  
  430.  
  431.